require 'erubis'
require 'rubygems'
require 'softlayer_api'
require 'pp'
require 'time'
require 'yaml'

module Depac
  class SLMgr
    private
    def initialize(softlayer_credentials)
      user = softlayer_credentials['username']
      key = softlayer_credentials['APIkey']

      @waitGrain=30
      @softLayer_product_package = SoftLayer::Service.new("SoftLayer_Product_Package", username: user, api_key: key);
      @softLayer_product_item_price = SoftLayer::Service.new("SoftLayer_Product_Item_Price", username: user, api_key: key);
      @softLayer_product_order = SoftLayer::Service.new( "SoftLayer_Product_Order", username: user, api_key: key);
      @softLayer_account_service = SoftLayer::Service.new( "SoftLayer_Account", username: user, api_key: key);
      @softLayer_container_disk_image_capture_template = SoftLayer::Service.new("SoftLayer_Container_Disk_Image_Capture_Template", username: user, api_key: key)
      @softLayer_virtual_guest = SoftLayer::Service.new("SoftLayer_Virtual_Guest", username: user, api_key: key)
      @softLayer_ticket = SoftLayer::Service.new("SoftLayer_Ticket", username: user, api_key: key)
      @softLayer_billing_item = SoftLayer::Service.new("SoftLayer_Billing_Item", username: user, api_key: key)
      @softLayer_network_vlan = SoftLayer::Service.new("SoftLayer_Network_Vlan", username: user, api_key: key)
      @softLayer_vg_block_device_template_group = SoftLayer::Service.new("SoftLayer_Virtual_Guest_Block_Device_Template_Group", username: user, api_key: key)
      @softLayer_virtual_disk_image = SoftLayer::Service.new("SoftLayer_Virtual_Disk_Image", username: user, api_key: key)
      @softlayer_product_package = SoftLayer::Service.new("SoftLayer_Product_Package", username: user, api_key: key)
      @softlayer_ssh_service = SoftLayer::Service.new("SoftLayer_Security_Ssh_Key", username: user, api_key: key)

      # Cache containing the set of item prices used to provision a CCI.
      @itemPriceCache = Hash.new

      # Master item price list that contains all the item prices retrieved from softlayer.
      @itemPricesAll = nil
    end

    # provisions a new vm using the name and template given
    # returns a hash with the new server info
    def provisionServer_internal(serverName, templateId, vmconfig, vmspecconfig,  keyid, addnl_storage=false, retry_count)
      result = ""
      templateObject = {
        'complexType' => "SoftLayer_Virtual_Guest",
        'hostname' => serverName,
        'domain' => vmconfig['domain'],
        'startCpus' => vmconfig['cpuCores'],
        'maxMemory' => vmconfig['maxMemory'],
        'hourlyBillingFlag' => vmconfig['hourlyBillingFlag'],
        'localDiskFlag' => vmconfig['localDiskFlag'],
        'datacenter'=> {'name'=> vmconfig['datacenter']},
        'networkComponents'=>[{'maxSpeed'=>vmconfig['networkmaxSpeed']}],
        'privateNetworkOnlyFlag'=>vmconfig['privateNetworkOnlyFlag'],
        'sshKeys'=>[{'id'=>keyid}]
      }
     
      if(vmspecconfig !=nil)
          Log.info("read datacenter info from vmspecconfig")
          templateObject['datacenter']={'name'=> vmspecconfig['datacenter']}
      else
          templateObject['datacenter']={'name'=> vmconfig['datacenter']}
      end
      
      if(vmspecconfig !=nil)
        if(vmspecconfig['frontEndVlanId'] != nil )
          templateObject['primaryNetworkComponent']={'networkVlan'=> {'id'=> vmspecconfig['frontEndVlanId']}}
        end
      else
        if(vmconfig['frontEndVlanId'] != nil )
          templateObject['primaryNetworkComponent']={'networkVlan'=> {'id'=> vmconfig['frontEndVlanId']}}
        end
      end
    
      if(vmspecconfig !=nil)
         if(vmspecconfig['backEndVlanId'] != nil)
            Log.info("read backEndVlanId info from vmspecconfig !")
            templateObject['primaryBackendNetworkComponent']={'networkVlan'=> {'id'=> vmspecconfig['backEndVlanId']}}
         end
      else
         if(vmconfig['backEndVlanId'] != nil )
           templateObject['primaryBackendNetworkComponent']={'networkVlan'=> {'id'=> vmconfig['backEndVlanId']}}
         end
      end     
     
     
      if ( templateId != nil )
        Log.warn("Provisioning server from an image template. Operating System and Disk Size configurations will be based on the image and configured values will be ignored!")
        templateObject['blockDeviceTemplateGroup']={'globalIdentifier' => templateId}
        if (addnl_storage)
          puts "Provisioning additional temporary storage..."
          templateObject['blockDevices'] = [{"device"=>"2", "diskImage"=>{"capacity"=>50}}]
        end
      else
        templateObject['operatingSystemReferenceCode'] = vmconfig['operatingSystemReferenceCode']
        templateObject['blockDevices']=[{"device"=>"0", "diskImage"=>{"capacity"=>vmconfig['diskSize']}}]
        if (addnl_storage)
          puts "Provisioning additional temporary storage..."
          templateObject['blockDevices'] << {"device"=>"2", "diskImage"=>{"capacity"=>50}}
        end
      end
      count = retry_count        
      begin
      	purchaseOrderDetails =  @softLayer_virtual_guest.createObject(templateObject)
      rescue Timeout::Error => e
      	count -= 1
      	Log.warn("Timeout Error: retrying! No of tries remaining - #{count}")
	    if count > 0
	      retry
	    else
	      Log.fatal_exit("Timeout Error: reached max retry count, exiting!")	      
	    end		
	  end
      return purchaseOrderDetails
    end  
    
    #TODO: Order Advanced NimSoft Advance Monitor
    def oderADMornitor_internal(packageID, priceID, ctGroupID, vmid)    
     
         ordertemplateObject = {
              'complexType' => 'SoftLayer_Container_Product_Order_Monitoring_Package',
              'packageId' => packageID, 
              'prices' => [{'id' => priceID}],
              'quantity' => 0,  
              'sendQuoteEmailFlag' => true,
              'useHourlyPricing' => true,
              'virtualGuests' => [{'id' => vmid}],
              'configurationTemplateGroups' => [{'id' => ctGroupID}]
              }
         
         Log.write("INFO", "orderTemplate: #{ordertemplateObject}")     
             
         begin
             verify_order = @softLayer_product_order.verifyOrder(ordertemplateObject)
             place_Order = @softLayer_product_order.placeOrder(ordertemplateObject)
             Log.write("INFO", "orderResult: #{place_Order}")
         rescue Exception => exception
             #puts "Unable to place order for nimsoft advanced monitor: #{exception}"
             Log.write("INFO", "Unable to place order for nimsoft advanced monitor: #{exception}")
         end  
          
    end  

    public
    
    #TODO: order nimsoft advanced montior
    def oderADMornitor(nodeInfoMap, envConfig)
         if nodeInfoMap[Depac::CloudDeploymentConstants::RUNTIME_NODES] !=nil && envConfig['nimsoftConfig']
               packageId=envConfig['nimsoftConfig']['packageId']
               priceId=envConfig['nimsoftConfig']['priceId']
               ctGroupId=envConfig['nimsoftConfig']['configurationTemplateGroups']
               
               Log.write("INFO", "NimSoft configure params: packageID=>#{packageId} priceId=>#{priceId} ctGroupId=>#{ctGroupId}")
                    
               if  packageId !=nil && priceId!=nil &&  ctGroupId !=nil  
                   rolesArr= envConfig['nimsoftConfig']['roles'].split(';')  
                   Log.write("INFO", "target roles to order advanced monitor are: #{rolesArr}")          
                   rolesArr.each do |role|
                      if nodeInfoMap[Depac::CloudDeploymentConstants::RUNTIME_NODES][role] !=nil
                         nodeinfoArr= nodeInfoMap[Depac::CloudDeploymentConstants::RUNTIME_NODES][role]                       
                         nodeinfoArr.each do |nodeinfo|
                              # call oderADMornitor_internal
                              Log.write("INFO", "Order advanced monitor for vmId: #{nodeinfo['vmid']}")
                              oderADMornitor_internal(packageId, priceId, ctGroupId, nodeinfo['vmid']) 
                         end
                      end 
                   end             
              end
        end
    end

    # TODO: Delete this. This should not be used since it assumes the location of apikey
    def init()
      # Read the softlayer credentials from apikey.yml and set them.
      # This activity is performed when this script gets loaded.
      apikeyfile = File.expand_path("~/apikey.yml")
      if (File.exists?(apikeyfile) && YAML.load_file(apikeyfile) != nil)
        $softlayer_credentials_apikey_file = YAML.load_file(apikeyfile)
        setCredentials($softlayer_credentials_apikey_file)
      end
    end

    # TODO: DELME. This function needs to be called explicitly to override the credentials read from apikey.yml.
#    def initializeCredentials(softlayer_credentials)
#      if(softlayer_credentials != nil)
#        setCredentials(softlayer_credentials)
#      else
#        if($softlayer_credentials_apikey_file == nil)
#          Log.write("ERROR","The softlayer credentials are not configured. The credentials should be configured either in the input configuration file or apikey.yml file located in your home directory.")
#          exit
#        end
#      end
#    end

    # Given the name of a flex image,  this method will find the newest one and return it only once it is ready
    # to be used as a template for a new provisioning...
    def waitForFlexImage(id)
      deployImage = findFlexImageByID(id)
      while ( deployImage['transactionId'] != nil )
        Log.write("INFO","Waiting for transaction #{deployImage['transactionId']} to complete for image...#{name}")
        sleep 10
        deployImage = findFlexImageByID(id)
      end
      return deployImage['id']
    end

    #  Given the name of a flex image,  this method will find the newest one and return it immediately.
    #  Use the wrapper method waitForFlexImage if you are trying to provision a vm based on this image.
    def findFlexImageByName(name)
      returnValue = nil
      bds = @softLayer_account_service.getBlockDeviceTemplateGroups()
      bds.each do | bd|
        if ( bd['name'] == name && bd['globalIdentifier']!=nil)
          if ( returnValue == nil )
            returnValue = bd
          else
            currentDate = Time.iso8601(returnValue['createDate'])
            nextDate = Time.iso8601(bd['createDate'])
            if ( nextDate > currentDate)
              returnValue = bd
            end
          end
        end
      end
      return returnValue
    end

    def findFlexImageByID(id)
      bds = @softLayer_account_service.getBlockDeviceTemplateGroups()
      bds.each do | bd|
        if ( bd['id'] == id )
          return bd
        end
      end
    end

    def printBillingItems()
      bis = @softLayer_account_service.getAllTopLevelBillingItems()
      #bis = @softLayer_account_service.getAllBillingItems()
      bis.each do |bi|
        Log.write("INFO", bi)
      end
    end

    # finds and cancels a billing item by server name
    def deleteInstance(serverName)
      bis = @softLayer_account_service.getAllTopLevelBillingItems()
      bis.each do |bi|
        hostname = bi['hostName']
        cancelDate = bi['cancellationDate']
        id = bi['id']
        if ( hostname == serverName)
          if ( cancelDate == nil )
            begin
              Log.write("INFO", "Cancelling order [#{id}] (for #{hostname})")
              ti = @softLayer_billing_item.object_with_id(id)
              ti.cancelService()
            rescue => error_reason
              Log.write("INFO","Failed to cancel order [#{id}] (for #{hostname}:  #{error_reason}")
            end
          end
        end
      end
    end

    def getVMDetailsByHostName(serverName)
      returnValue = ""
      instances = @softLayer_account_service.getHourlyVirtualGuests()
      instances.each do|instance|
        if ( instance['hostname'] == serverName  )
          returnValue=instance
        end
      end
      return returnValue
    end

    # Just prints the instance hash for each vm that we can see.
    def printVMList()
      returnValue = ""
      instances = @softLayer_account_service.getHourlyVirtualGuests()
      instances.each do|instance|
        Log.write("INFO", instance)
      end
    end

    def snapShotVM(id, imageName, idIsServerName, useFlexImage)
      returnValue=""
      if ( idIsServerName )
        instance = getVMDetailsByHostName(id)
      else
        vg=@softLayer_virtual_guest.object_with_id(id)
        instance = vg.getObject()
      end
      begin
        id=instance['id']
        ip=instance['primaryBackendIpAddress']
        hostname=instance['hostname']
        fqdn=instance['fullyQualifiedDomainName']
        @softLayer_container_disk_image_capture_template = {
          "name" => imageName,
        }

        if ( useFlexImage )
          Log.write("INFO","Capturing flex image #{imageName} for: id=#{id}, ip=#{ip}, host=#{fqdn}")
          captureTemplate = vg.captureImage(@softLayer_container_disk_image_capture_template)
        else
          Log.write("INFO", "Capturing standard image #{imageName} for: id=#{id}, ip=#{ip}, host=#{fqdn}")
          blockDevices=vg.getBlockDevices()
          archiveDevices = []
          blockDevices.each() do | blockDevice|
            diskImage=@softLayer_virtual_disk_image.object_with_id(blockDevice['diskImageId'])
            #Only add the first disk drive to image template. Skips Swap and other the tmp provisioned hdd
            if(blockDevice['device']=="0")
              archiveDevices << blockDevice
            end
          end
          captureTemplate=vg.createArchiveTransaction(imageName,archiveDevices,"#{imageName} - created #{Time.now.strftime("%Y%m%d%H%M")}")
          Log.write("INFO","Sleeping for a few seconds to see if it helps let transactions get started so we can wait properly")
          sleep 7
        end
        Log.write("INFO", captureTemplate)
        returnValue=captureTemplate['id']
        return returnValue
      rescue => error_reason
        Log.write("ERROR", "#{error_reason}... retrying in #{@waitGrain} seconds.")
        sleep @waitGrain
        return nil
      end
    end

    def waitForVMTransactionsToComplete(id)
      begin
        vg=@softLayer_virtual_guest.object_with_id(id)

        ip = vg.getPrimaryBackendIpAddress()
        serverName = vg.getObject()['hostname']

        while ( ip == nil || vg.getActiveTransactions().size() > 0 || !vg.isBackendPingable() )
          activeTran=vg.getActiveTransaction()
          txn="#{activeTran['transactionStatus']['name']}"
          Log.write("INFO","Waiting (#{@waitGrain} seconds) [#{id}] [#{serverName}] [#{ip}] [status=#{txn}]")
          sleep @waitGrain
        end
        return vg.getObject()
      rescue => error_reason
        if ( ! error_reason.instance_of?(NoMethodError) )
          Log.write("ERROR", error_reason.message)
          Log.write("INFO","Waiting (#{@waitGrain} seconds) [#{id}] [#{serverName}] [#{ip}]")
        end
        sleep @waitGrain
        return waitForVMTransactionsToComplete(id)
      end

    end

    def getVirtualGuestObject(id)
      vg = @softLayer_virtual_guest.object_with_id(id)
      return vg
    end

    def isTransactionComplete(vg)
      isComplete = false
      begin
        ip = vg.getPrimaryBackendIpAddress()
        serverName = vg.getObject()['hostname']

        if (ip == nil || vg.getActiveTransactions().size() > 0)
          activeTran = vg.getActiveTransaction()
          txn="#{activeTran['transactionStatus']['name']}"
          Log.write("INFO","[#{serverName}] [#{ip}] [status=#{txn}]")
        else
          isComplete = true
        end
      rescue => error_reason
        Log.write("INFO","[#{serverName}] [#{ip}]")
      end
      return isComplete
    end

    def waitForSomeTime(elapsedTime)
      if elapsedTime < @waitGrain
        sleepTime = @waitGrain - elapsedTime
        sleep sleepTime
      end
    end

    def writePurchaseOrderDetails(cloneServer, serverDetails)
      filename="#{cloneServer}.txt"
      File.open(filename,"w") {|f|
        f.puts(serverDetails)
        f.close
      }
    end

    def getVirtualGuestIdFromOrderDetails(poDetails,newHost)
      #orderDetails=poDetails['orderDetails']
      #vgs = orderDetails['virtualGuests']
      #id = poDetails['id']
      return poDetails['id']
    end

    # vms will be an array of hashes. What will be returned through this
    # method is a copy of the vms array of hashes along with order/ip details
    # of the provisioned machines.
    def provisionVMs(vms, buildlabel, wsPubKeyPath, addnl_storage = false, retry_count)
      keyid = registerSSHkey(wsPubKeyPath)

      vms_withinfo = vms.clone
      lock = Mutex.new

      Log.info("Starting VM provisioning...")
      threads = []
      vms_withinfo.each() do |vm|
        if ( vm['servername'] != nil )
          servername = "#{vm['servername']}".downcase
          chefnodename = "#{buildlabel}-#{servername}"
        else
          servername = "#{buildlabel}-#{vm['snaprole'].downcase}"
          chefnodename = "#{buildlabel}-#{vm['snaprole'].downcase}"
        end

        result = provisionServer(servername , vm['srcimageid'], vm['vmconfig'], nil, keyid, addnl_storage, retry_count)

        vmid = getVirtualGuestIdFromOrderDetails(result,servername)
        orderId = result['orderId']

        threads << Thread.new(vm) {
          vg=waitForVMTransactionsToComplete(vmid)

          # modifications to the vms_withinfo object is not thread safe
          lock.synchronize do
            vm['ip'] = vg['primaryBackendIpAddress']
            vm['hostname'] = vg['hostname']
            vm['fqdn'] = vm['hostname']+"."+vm['vmconfig']['domain']
            vm['chefnodename'] = chefnodename
            vm['vmid'] = vmid
            vm['orderid'] = orderId
          end
        }
      end

      threads.each { |aThread| aThread.join }
      Log.info("...provisioning completed!")

      return vms_withinfo
    end

    def provisionServer(serverName, imageId, vmconfig, vmspecconfig, keyid, addnl_storage = false, retry_count)
      taillog = imageId ? " from image #{imageId}" : ""
      Log.write("INFO","Provisioning server '#{serverName}'#{taillog}")
      purchaseOrderDetails = provisionServer_internal(serverName, imageId, vmconfig, vmspecconfig, keyid, addnl_storage, retry_count)
      Log.write("INFO","Completed ordering server '#{serverName}'#{taillog}")
      Log.write("INFO","Purchase Details: '#{purchaseOrderDetails}' ")
      return purchaseOrderDetails
    end

    def snapshotBuildDeployment(config)
      Log.info("Creating build snapshots")
      Log.info("Waiting for 10 seconds before taking snapshots...")
      sleep 10
      vms = config.vms
      threads = []
      snapshots = []
      vms.each() do |node|
        threads << Thread.new(node) {
          snaprole=node['snaprole']
          imagename="#{config.buildlabel} - SSFS #{snaprole} Snapshot"
          vmid=node['vmid']
          waitForVMTransactionsToComplete(vmid)
          imageId = snapShotVM(vmid, imagename, false, false)
          snapshot = {id: imageId, name: imagename}
          waitForVMTransactionsToComplete(vmid)
          Log.info("Created snapshot: ")
          Log.info(snapshot)
          snapshots << snapshot
        }
      end

      threads.each { |aThread| aThread.join }

      filename="#{DeplConfig::DEP_DATA}/SnapShotReport_#{config.buildlabel}.yml"
      File.open(filename,"w") {|f|
        f.puts(snapshots.to_yaml)
        f.close
      }
    end

    def deprovisionBuildDeployment(vms, wait=true)
      threads = []
      Log.info("Deprovisioning build deployment...")
      Log.info("Waiting for 10 seconds before deprovisioning VMs...")
      sleep 10
      vms.each() do |node|
        threads << Thread.new(node) {
          vmid=node['vmid']
          hostname=node['hostname']
          waitForVMTransactionsToComplete(vmid) if wait
          vg=@softLayer_virtual_guest.object_with_id(vmid)
          bi=vg.getBillingItem()
          orderId=bi['id']
          Log.write("INFO","Cancelling order [#{orderId}] for [host=#{hostname}] [vmid=#{vmid}]")
          ti = @softLayer_billing_item.object_with_id(orderId)
          ti.cancelService()
        }
      end
      threads.each { |aThread| aThread.join }
    end

    # Add by CDL to support delete build snapshot from snapshotreportFile which is new format for Price
    #- id: 
    #  name:      
    def deleteBuildSnapshots_new(snapshotReportFile)
      Log.write("INFO", "Deleting build snapshots for build #{snapshotReportFile} with method deleteBuildSnapshots_new")    
      threads = []
      if (File.exists?(snapshotReportFile) && YAML.load_file(snapshotReportFile) != nil)
        snapshotReport = YAML.load_file(snapshotReportFile)
        snapshotReport.each() do |image|
          snapid = image["id"]
          snapname = image["name"]
          if ( snapid == nil )
              bds = @softLayer_account_service.getBlockDeviceTemplateGroups()
              bds.each do | bd|
                # TODO:  This isn't really enough to identify the snapid
                # when there is more than one deployment for a given build-label...
                if ( bd['name'] == snapname )
                  snapid = bd['id']
                  Log.write("INFO", "#{snapname} snapshot ID is: [#{snapid}]")
                end
              end
          end
          threads << Thread.new(image) {
              Log.write("INFO", "Deleting #{snapname} [#{snapid}]")
              deleteSnapshot(snapid)
          }
       end
     end
     threads.each { |aThread| aThread.join }
    end 

    def deleteBuildSnapshots(snapshotReportFile)
      Log.write("INFO", "Deleting build snapshots for build #{snapshotReportFile}")
      threads = []
      if (File.exists?(snapshotReportFile) && YAML.load_file(snapshotReportFile) != nil)
        snapshotReport = YAML.load_file(snapshotReportFile)
        vms=snapshotReport[:vms]
        vms.each() do |node|
          snapshots=node['snapshots']
          snapshots.each() do |snapshot|
            snapid = snapshot['snapid']
            snapname = snapshot['snapname']
            useFlexImage = snapshot['useFlexImage']
            if ( ! useFlexImage )
              bds = @softLayer_account_service.getBlockDeviceTemplateGroups()
              bds.each do | bd|
                # TODO:  This isn't really enough to identify the snapid
                # when there is more than one deployment for a given build-label...
                if ( bd['name'] == snapname )
                  snapid = bd['id']
                end
              end
            end

            threads << Thread.new(node) {
              Log.write("INFO", "Deleting #{snapname} [#{snapid}]")
              deleteSnapshot(snapid)
            }
          end
        end
      else
        Log.write("INFO", "Invalid snapshot file given:  #{snapshotReportFile}")
      end
      threads.each { |aThread| aThread.join }
    end

    def deleteSnapshot(snapshotId)
      bdtg = @softLayer_vg_block_device_template_group.object_with_id(snapshotId)
      #Log.write("INFO", bdtg.getObject())
      bdtg.deleteObject()
    end

    def shareSnapshot(snapshotId, accountId)
      bdtg = @softLayer_vg_block_device_template_group.object_with_id(snapshotId)
      bdtg.permitSharingAccess(accountId)
    end

    def shareBuildSnapshots(snapshotReportFile, accountname )
      accountid=lookupAccount(accountname)
      if (accountid ==nil)
      	Log.fatal_exit("Invalid account name givendd:  #{accountname}")
      end
      if ( File.exists?(snapshotReportFile) && YAML.load_file(snapshotReportFile) != nil)
        snapshotReport = YAML.load_file(snapshotReportFile)                 
        snapshotReport.each() do |snapshot|
            snapid = snapshot[:id]
            snapname = snapshot[:name]                 
            bds = @softLayer_account_service.getBlockDeviceTemplateGroups()
            bds.each do | bd|
                # TODO:  This isn't really enough to identify the snapid
                # when there is more than one deployment for a given build-label...\
                if ( bd['name'] == snapname && bd['globalIdentifier'] != nil)
                  snapid = bd['id']

                  begin
                    Log.write("INFO", "Sharing #{snapname} [#{snapid}] with #{accountid}")
                    bdtg = @softLayer_vg_block_device_template_group.object_with_id(snapid)
                    bdtg.permitSharingAccess(accountid)
                  rescue => error_reason
                    Log.write("ERROR", "Sharing #{snapname} [#{snapid}] with #{accountid} failed!")
                    Log.write("ERROR", error_reason.message)
                  end
                end            
            end
         end    
      else
        Log.write("INFO", "Invalid snapshot file given:  #{snapshotReportFile}")
      end
    end

    def lookupAccount(accountname)
    accounts=nil
    accid = nil
     if File.exists?("config/accounts.yml")
     	accounts=YAML.load_file("config/accounts.yml")
     else
     	accounts=YAML.load_file("config/accounts.yml.sample")
     end      
      accounts[:Accounts].each do|account|
        if ( account['name'] == accountname )
          accid = account['id']
        end
      end
      return accid
    end

    def deleteSnapshotsByBuildLabel(buildlabel)
      bds = @softLayer_account_service.getBlockDeviceTemplateGroups()
      bds.each do | bd|
        puts "#{bd['name']}.include?#{buildlabel}"
        if ( bd['name'].include?buildlabel )
          deleteSnapshot(bd['id'])
        end
      end
    end

    def getPrivateVlans()
      privateVlans = @softLayer_account_service.getPrivateNetworkVlans()

      privateVlans.each do |privateVlan|
        softLayer_network_vlan_object = @softLayer_network_vlan.object_with_id(privateVlan['id'])
        privateVlan['hostname'] = softLayer_network_vlan_object.getPrivateVlan()['primaryRouter']['hostname']

        primary_subnets = softLayer_network_vlan_object.getPrimarySubnets()
        privateVlan['totalIpAddresses'] = primary_subnets[0]['totalIpAddresses']
        privateVlan['usableIpAddressCount'] = primary_subnets[0]['usableIpAddressCount']
      end

      return privateVlans
    end

    def findVlanDetailsById(vlanId)
      privateVlans = getPrivateVlans()

      privateVlans.each do |privateVlan|
        if(privateVlan['id'] == vlanId)
          return privateVlan
        end
      end
      return nil
    end

    # Delete/de-provision instance by primary backend ip address
    def deleteInstanceByIP(ipAddress)
      vg = @softLayer_virtual_guest.findByIpAddress(ipAddress)
      if(vg != nil)
        found = true
        hostname = vg['hostname']
        primaryBackendIpAddress = vg['primaryBackendIpAddress']
        vmid = vg['id']
        deleteInstanceByVMID(vmid)
      else
        Log.write("INFO", "Unable to cancel order for [ip=#{ipAddress}] which has already been cancelled")
      end
    end

    # Delete/de-provision instance by vmid
    def deleteInstanceByVMID(vmid)
      vg = @softLayer_virtual_guest.object_with_id(vmid)
      hostname = vg.getObject()['hostname']
      ipAddress = vg.getObject()['primaryBackendIpAddress']

      bi = vg.getBillingItem()      

      if ( bi == nil )
        Log.write("INFO", "Unable to cancel order for [host=#{hostname} ip=#{ipAddress}] which has already been cancelled")
      else
        begin
          cancelDate = bi['cancellationDate']
		  orderId = bi['id']
		  Log.write("INFO", "Cancelling order [#{orderId}] for [host=#{hostname} ip=#{ipAddress}]")
          ti = @softLayer_billing_item.object_with_id(orderId)
          ti.cancelService()
        rescue => error_reason
          Log.write("INFO", "Failed to cancel order [#{orderId}] for [host=#{hostname} ip=#{ipAddress}: #{error_reason}]")
        end
      end
    end

    def changePowerSate(vmid, powerState)
      vg = @softLayer_virtual_guest.object_with_id(vmid)
      currectPowerState = vg.getPowerState()

      if(powerState == 'On')
        if(currectPowerState['keyName'] != 'RUNNING')
          vg.powerOn()
        end
      end

      if(powerState == 'Off')
        if(currectPowerState['keyName'] != 'HALTED')
          vg.powerOff()
        end
      end
    end

    # Retrieves the item price record based on the category name and item description from softlayer
    def getItemPrice(categoryName, itemDecsription)
      # Storing the entire list of item prices for future use. Multiple api invocations can be avaoided.
      if(@itemPricesAll == nil)
        $virtual_guest_package = @softlayer_product_package.object_with_id(46)
        @itemPricesAll = $virtual_guest_package.object_mask("id", "hourlyRecurringFee", "item.description", "categories").getItemPrices()
      end

      return findMatchingItemPrice(@itemPricesAll, categoryName, itemDecsription)
    end

    # Retrieves the item price id based on the category name and item description. If the item
    # price is not available in the cache, the corr. records are fetched from softlayer.
    def getItemPriceId(categoryName, itemDecsription)
      # Check the cache for item price id
      key = "#{categoryName}:#{itemDecsription}"
      itemPriceId = @itemPriceCache[key]

      # If not found, check the master item price list for item price id.
      # Store the item price record retrieved from master list in the cache.
      if(itemPriceId == nil)
        itemPrice = getItemPrice(categoryName, itemDecsription)
        if(itemPrice != nil)
          itemPriceId = itemPrice['id']
          @itemPriceCache[key] = itemPriceId
        end
      end
      return itemPriceId
    end

    # Finds the item price record based on the category name and item description
    def findMatchingItemPrice(item_prices, categoryName, itemDecsription)
      returnValue = nil
      item_prices.each do |item_price|
        description = item_price['item']['description']
        catName = item_price['categories'][0]['name']
        hourlyRecurringFee = item_price['hourlyRecurringFee']
        #id = item_price['id']
        #itemid = item_price['itemId']

        # Some items like "0 GB Bandwidth" have 2 options, with hourly recurring fee and without it.
        # The item with hourlyRecurringFee is chosen, as we are provisioning CCIs with hourly pricing.
        if (description == itemDecsription and catName == categoryName and hourlyRecurringFee != nil)
          returnValue = item_price
          #Log.write("INFO", "Discovered: #{description}: id=#{id} itemId=#{itemid}")
          #Log.write("INFO", item_price)
          break
        end
      end
      return returnValue
    end

    def registerSSHkey(pubKeyPath)
      pubKey = File.read(File.expand_path(pubKeyPath)).strip
      registeredKeys = @softLayer_account_service.getSshKeys()
      keyid=nil
      if(registeredKeys.length >0)
        registeredKeys.each() do |key|
          if(key['key'].strip==pubKey.strip)
            keyid = key['id']
          end
        end
      end
      if(keyid==nil)
        keyObj = {
          'label' => 'provisioningKey',
          'key' => pubKey
        }
        output = @softlayer_ssh_service.createObject(keyObj)
        keyid = output['id']
        Log.info("Registerd key with ID: #{keyid}")

      else
        Log.info("key #{keyid} already registered in softlayer, not registering it")
      end
      return keyid
    end

    def validateBuildEarParams(params)
      params = params.split(' ')
      earName = nil
      params.each() do |x|
        if(x.index('earfile')!=nil)
          earName = x.split('=')[1]
        end
      end
      warlist = nil
      params.each() do |x|
        if(x.index('warfiles')!=nil)
          warlist = x.split('=')[1]
        end
      end
      warlist = warlist.split(',')
      if(earName == nil || earName.strip == '')
        Log.write("ERROR","buildEarParams is missing earName  ,please provide a -Dearfile param.")
        exit
      end
      if(warlist == nil || warlist.length ==0 || warlist[0].strip == '')
        Log.write("ERROR","buildEarParams is missing warfiles  ,please provide a -Dwarfiles param with atleast one war file name.")
        exit
      end
      return earName
    end
  end
end